import os, sys, datetime, time, thread
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer

def execute(command):
  print command
  os.system(command)

def getCommand():
  if len(sys.argv) <= 1:
    return None
  return sys.argv[1]

def superOpenW(path):
  parent = os.path.split(path)[0]
  if not os.path.exists(parent):
    os.makedirs(parent, 0777)
  return open(path, "w")

def superMkdir(path, rmFirst=False):
  if rmFirst and os.path.exists(path): execute("rm -rf '%s'" % path)
  if os.path.exists(path): return
  os.makedirs(path, 0777)

def lastfind(text, token):
  s = 0
  result = -1
  while True:
    p = text.find(token, s)
    if p == -1:
      return result
    result = p
    s = p + 1

def replaceVarDirectoriesWithRamfsLinks(createTmpInfrastructureOnly=False):
  replacementMap = {
    "/home/rchbiu/.libreoffice/3/user/extensions/tmp": "/tmp/vars/libreoffice",
    "/home/rchbiu/.kde/tmp-ubuntu": "/tmp/vars/kde",
    "/home/rchbiu/.cache/software-center/software-center-agent.db.tmp": "/tmp/vars/software-center",
    "/home/rchbiu/.mozilla/firefox/qmiwc28h.default/Cache": "/tmp/vars/firefox",
    "/home/rchbiu/.config/google-chrome/Temp": "/tmp/vars/chrome-tmp",
    "/home/rchbiu/.cache": "/tmp/vars/chrome",
    "/home/rchbiu/.config/google-chrome": "/tmp/vars/chrome-config-db",
    "/var/tmp": "/tmp/vars/vartmp"
  }
  for k, v in replacementMap.items():
    if not os.path.exists(v):
      os.makedirs(v, 0777)
      execute("chmod -R 0777 '%s'" % v)
    if not createTmpInfrastructureOnly:
      if not os.path.exists(k):
        os.makedirs(k, 0777)
      execute("rm -rf '%s' && ln -s '%s' '%s' && sudo chown -R rchbiu '%s' && sudo chown -R rchbiu '%s'" % (k, v, k, v, k))
  if createTmpInfrastructureOnly:
    return
  execute("sudo chown -R rchbiu '/home/rchbiu'")
  execute("sudo chmod -R 0777 '/tmp'")
  fstabfile = "/etc/fstab"
  fstabtxt = open(fstabfile).read()
  if fstabtxt.find("/var/log") == -1:
    if not fstabtxt.endswith("\n"):
      fstabtxt += "\n"
    fstabtxt += "# added by pybuntu:\n"
    fstabtxt += "#none\t/tmp\ttmpfs\tdefaults\t0\n"
    fstabtxt += "#none\t/var/log\ttmpfs\tdefaults\t0\n"
    updfstab = "/tmp" + fstabfile
    f = superOpenW(updfstab)
    f.write(fstabtxt)
    f.close()
    execute("mv '%s' '%s'" % (fstabfile, fstabfile + ".back"))
    execute("mv '%s' '%s' && chmod 755 '%s'" % (updfstab, fstabfile, fstabfile))
    execute("nano '%s'" % fstabfile)

def insertOnUbuntuLoadedToRcLocal():
  rclocalfile = "/etc/rc.local"
  rclocalbuf = open("/etc/rc.local").read()
  startupcommand = "python " + os.path.abspath(sys.argv[0]) + " on-ubuntu-loaded\n"
  if rclocalbuf.find(startupcommand) == -1:
    p = lastfind(rclocalbuf, "exit 0")
    rclocalbufsuffix = rclocalbuf[p:]
    rclocalbuf = rclocalbuf[:p]
    if not rclocalbuf.endswith("\n"):
      rclocalbuf += "\n"
    rclocalbuf += "# added by pybuntu:\n"
    rclocalbuf += "#" + startupcommand
    rclocalbuf += rclocalbufsuffix
    rclocalupd = "/tmp" + rclocalfile
    f = superOpenW(rclocalupd)
    f.write(rclocalbuf)
    f.close()
    execute("mv '%s' '%s'" % (rclocalfile, rclocalfile + ".back"))
    execute("mv '%s' '%s' && chmod 755 '%s'" % (rclocalupd, rclocalfile, rclocalfile))
    execute("nano " + rclocalfile)

def getNoncommentedLines(text):
  result = []
  for line in text.split("\n"):
    line = line.strip()
    p = line.find("#")
    if p > -1:
      line = line[:p];
    line = line.strip()
    if len(line) == 0: continue;
    result.append(line)
  return result

class EasyInstaller:
  def __init__(self):
    self.__software = []
  def setSoftware(self, software):
    self.__software = software
  def __call__(self):
#    command = "sudo apt-get install " + " ".join(self.__software)
#    execute(command)
    for sp in self.__software:
      command = "sudo apt-get install -y " + sp
      execute(command)
      execute("sudo apt-get clean")

# TODO: was used only by java, neverused now.
class AddAptRepositoryInstaller:
  def __init__(self, software, repository):
    self.__software = software
    self.__repository = repository
  def __call__(self):
    command = "sudo add-apt-repository ppa:%s && sudo apt-get update && apt-get install -y %s" % (self.__repository, self.__software)
    execute(command)
# TODO: was used only by java, neverused now.

class SaveDebInstaller:
  SAVE_DEBS_TO_FOLDER = "/tmp/.pybuntu-debs"
  def __init__(self, debLocation, onDpkgInstallCalled=None):
    self.__debLocation = debLocation
    if onDpkgInstallCalled is None:
      onDpkgInstallCalled = self.__nop
    self.__onDpkgInstallCalled = onDpkgInstallCalled
  def __call__(self):
    saveDebToFolder = SaveDebInstaller.SAVE_DEBS_TO_FOLDER
    if not os.path.exists(saveDebToFolder): os.makedirs(saveDebToFolder, 0777);
    savedDeb = os.path.join(saveDebToFolder, os.path.split(self.__debLocation)[1])
    command = "cd '%s' && wget '%s' && sudo dpkg -i '%s' && sudo chmod 777 '%s'" % (saveDebToFolder, self.__debLocation, savedDeb, savedDeb)
    execute(command)
    self.__onDpkgInstallCalled()
  def __nop(self):
    pass

def installGoogleChromePatch():
  installDepsCommand = "sudo apt-get install -y libcurl3 libnspr4-0d"
  execute(installDepsCommand)
  reInstallChgomeCommand = "cd '%s' && sudo apt-get -f install -y " % SaveDebInstaller.SAVE_DEBS_TO_FOLDER
  execute(reInstallChgomeCommand)

def installSkypePatch():
  reInstallSkypeCommand = "cd '%s' && sudo apt-get -f install -y " % SaveDebInstaller.SAVE_DEBS_TO_FOLDER
  execute(reInstallSkypeCommand)

def askUsetToDownload(webPage, outputDir):
  tmpAskMessage = "/tmp/.pybuntu-ask-message"
  f = superOpenW(tmpAskMessage)
  f.write("Please download blueprint from web page\n(%s)\n and save it to\n'%s'\n" % (webPage, outputDir))
  f.close()
  #os.system(webPage)
  os.system("nano '%s'" % tmpAskMessage)

class BlueprintInstaller:
  def __init__(self, blueprintLocation, vendorPage=None):
    self.__blueprintLocation = blueprintLocation
    self.__vendorPage = vendorPage
  def __pleaseDownload(self):
    pass
  def __call__(self):
    blueprintDir = "/tmp/.pybuntu-blueprint"
    if not os.path.exists(blueprintDir):
      os.makedirs(blueprintDir, 0777);
      execute("chmod -R 777 %s" % blueprintDir)
    bpDirContent = os.listdir(blueprintDir)
    if self.__vendorPage is not None:
      askUsetToDownload(self.__vendorPage, blueprintDir)
    else:
      downloadCommand = "cd '%s' && wget '%s'" % (blueprintDir, self.__blueprintLocation)
      execute(downloadCommand)
    blueprintFile = None
    for bp in os.listdir(blueprintDir):
      if bp not in bpDirContent:
        blueprintFile = bp
    if blueprintFile is None:
      print "Failed to find new blueprint in '%s'" % blueprintDir
      return
    installCommand = "cd '%s' && chmod 777 '%s' && sudo bash './%s'" % (blueprintDir, blueprintFile, blueprintFile)
    execute(installCommand)

def loadAcpicallModule():
  acpiInstallationDir = "/bin/pybuntu-ascpicall"
  acpiModule = os.path.join(acpiInstallationDir, "acpi_call.ko")
  loadCmd = "sudo insmod '%s'" % acpiModule
  execute(loadCmd)

#todo: remove if not used
def switchIonGPU(action):
  acpiInstallationDir = "/bin/pybuntu-ascpicall"
  switchCmd = "'%s' '%s'" % (os.path.join(acpiInstallationDir, "asus1215n.sh"), action)
  execute(switchCmd)

def installAcpiIonShutdown():
  acpiTmpDir = "/tmp/.pybuntu-acpucall"
  if os.path.exists(acpiTmpDir): execute("rm -rf '%s'" % acpiTmpDir)
  acpiSourceDir = os.path.join(os.path.split(os.path.abspath(sys.argv[0]))[0], "acpi_call")
  copyCommand = "cp -R '%s' '%s'" % (acpiSourceDir, acpiTmpDir)
  execute(copyCommand)
  execute("sudo chmod -R 777 '%s'" % acpiTmpDir)
  buildCommand = "cd '%s' && make" % acpiTmpDir
  execute(buildCommand)
  acpiInstallationDir = "/bin/pybuntu-ascpicall"
  superMkdir(acpiInstallationDir, True)
  copyPattern = "cp %s/%s %s"
  for acpiFile in ["*.sh", "*.ko", ]:
    copyCmd = copyPattern % (acpiTmpDir, acpiFile, acpiInstallationDir)
    execute(copyCmd)
  chmodCmd = "sudo chmod -R 555 '%s'" % acpiInstallationDir
  execute(chmodCmd)
  loadAcpicallModule()

def exclude(a, b):
  result = []
  for e in a:
    if not e in b:
      result.append(e)
  return result

def recursivelyExtract(arch):
  parent = os.path.split(arch)[0]
  print parent
  oldContent = os.listdir(parent)
  outputflag = ""
  if arch.endswith(".exe"):
    outputflag = "-o./main-ru-en-dict-tmp"
  execute("cd %s && 7z x %s %s" % (parent, outputflag, arch))
  unpacked = exclude(os.listdir(parent), oldContent)
  if len(unpacked) == 1:
    uext = os.path.splitext(unpacked[0])[1]
    if uext in [".tar", ".bz2"]:
      return recursivelyExtract(os.path.join(parent, unpacked[0]))
  if len(unpacked) == 0:
    print "Failed to extract from: '%s'" % arch
  if arch.endswith(".exe"):
    execute("mv %s %s" % (os.path.join(parent, "main-ru-en-dict-tmp/content"), os.path.join(parent, "main-ru-en-dict")))
    execute("rm -rf %s" % os.path.join(parent, "main-ru-en-dict-tmp"))
  return unpacked

def installDictionaries():
  additionalDictionaties = [
    "http://ignum.dl.sourceforge.net/project/goldendict/goldendict/1.0/GoldenDict-1.0.1-1-EnRuEn-Install.exe",
    #"http://sunet.dl.sourceforge.net/project/xdxf/dicts-XDXF/sdict05/comn_sdict05_german-english.tar.bz2",
    #"http://kent.dl.sourceforge.net/project/xdxf/dicts-XDXF/sdict05/comn_sdict_axm05_English_German.tar.bz2",
    #"http://switch.dl.sourceforge.net/project/xdxf/dicts-XDXF/sdict05/comn_sdict05_german_rus2.tar.bz2",
    #"http://garr.dl.sourceforge.net/project/xdxf/dicts-XDXF/sdict05/comn_sdict05_rus_ger.tar.bz2",
    "ftp://ftp.sbor.net/pub/unix/Linux/slackware/left/stardict-german_rus2-2.4.2-noarch-1left.tgz",
    #"",
  ]
  dictdownTmp = "/tmp/.pybuntu-dictionaries"
  if not os.path.exists(dictdownTmp):
    os.makedirs(dictdownTmp)
  wgetCommands = [" wget %s " % dictUrl for dictUrl in additionalDictionaties]
  execute("cd %s && %s" % (dictdownTmp, " && ".join(wgetCommands)))
  dictFolders = []
  for d in os.listdir(dictdownTmp):
    dictRoot = recursivelyExtract(os.path.join(dictdownTmp, d))
    dictFolders.extend(dictRoot)
  dictionariesStore = "/home/rchbiu/Documents/dictionaries"
  if not os.path.exists(dictionariesStore):
    os.makedirs(dictionariesStore)
    execute("sudo chown -R rchbiu %s" % dictionariesStore)
  for d in dictFolders:
    execute("mv %s %s" % (os.path.join(dictdownTmp, d), dictionariesStore))

def installEclipse():
  eclipseGzLoc = "http://mirror.cc.columbia.edu/pub/software/eclipse/technology/epp/downloads/release/indigo/SR1/eclipse-java-indigo-SR1-linux-gtk.tar.gz"
  eclipseFinalDestination = "/storage/programs/dev"
  gzDir = "/tmp/.pybuntu-gz"
  if not os.path.exists(gzDir): os.makedirs(gzDir, 7777)
  downloadCommand = "cd '%s' && wget '%s'" % (gzDir, eclipseGzLoc)
  execute(downloadCommand)
  eclipseGz = os.path.split(eclipseGzLoc)[1]
  folderContent = os.listdir(gzDir)
  extractCommand = "cd '%s' && 7z x '%s'" % (gzDir, eclipseGz)
  execute(extractCommand)
  eclipseTar = None
  for f in os.listdir(gzDir):
    if f not in folderContent:
      eclipseTar = f
  if eclipseTar is None:
    print "Failed to find .tar '%s'" % str(os.listdir(gzDir))
    return
  extractCommand = "cd '%s' && 7z x '%s'" % (gzDir, eclipseTar)
  execute(extractCommand)
  if not os.path.exists(eclipseFinalDestination): os.makedirs(eclipseFinalDestination, 0777);
  mv2finalCommand = "cd '%s' && mv eclipse '%s'" % (gzDir, eclipseFinalDestination)
  execute(mv2finalCommand)
  chmodAccessCommand = "sudo chmod -R 777 '%s'" % "/storage"
  execute(chmodAccessCommand)
#  chmodExecCommand = "sudo chmod a+x '%s'" % os.path.join(eclipseFinalDestination, "eclipse", "eclipse")
#  execute(chmodExecCommand)
  f = superOpenW(os.path.join(eclipseFinalDestination, "eclipse.plugins.urls.txt"))
  f.write("""\
# pydev:
# CTD:
# HTML editor:
""")
  f.close()
  f = superOpenW("/home/rchbiu/shortcuts/eclipse")
  f.write("""\
#!/bin/bash
%s
""" % os.path.join(eclipseFinalDestination, "eclipse", "eclipse"))
  f.close()
  mkshortCommand = "sudo chmod a+x ~/shortcuts/eclipse"
  execute(mkshortCommand)

def getSoftwareInstallers(software):
  name2installer = {
    "google-chrome": SaveDebInstaller("https://dl.google.com/linux/direct/google-chrome-stable_current_i386.deb", installGoogleChromePatch),
    "google-talkplugin": SaveDebInstaller("http://dl.google.com/linux/direct/google-talkplugin_current_i386.deb"),
    "google-music-manager": SaveDebInstaller("http://dl.google.com/linux/direct/google-musicmanager-beta_current_i386.deb"),
    "skype": SaveDebInstaller("http://download.skype.com/linux/skype-ubuntu_2.2.0.35-1_i386.deb", installSkypePatch),
    "acpicall-ion-shutdown": installAcpiIonShutdown,
    "additional-dictionaries-for-goldendict": installDictionaries,
    "picasa": SaveDebInstaller("http://dl.google.com/linux/deb/pool/non-free/p/picasa/picasa_3.0-current_i386.deb"),
    "teamviewer": SaveDebInstaller("http://www.teamviewer.com/download/teamviewer_linux.deb"),
    "vmplayer": BlueprintInstaller(None, "https://www.vmware.com/tryvmware/pa/activate.php?p=player&k=f0ea6d5562706aae210f7c6014b6ced5&cmp=EMC-PlayerEvalActivation&li=license"),
    "eclipse": installEclipse,
    }
  result = [EasyInstaller()]
  easyToInstalList = []
  for s in software:
    if s in name2installer.keys():
      result.append(name2installer[s])
    else:
      easyToInstalList.append(s)
  result[0].setSoftware(easyToInstalList)
  if len(easyToInstalList) == 0: result = result[1:]
  return result

def proposeSoftwareInstallation():
  proposedSoftwareText = """\
# General
smplayer
krusader
rhythmbox
google-chrome
google-talkplugin
google-music-manager
goldendict
#additional-dictionaries-for-goldendict
guake
#~~~flash-player-plugin-firefox && chrome
#~~~ addons && veb apps
#midori
#picasa
#skype
#pidgin

# System
acpi
acpicall-ion-shutdown
smbfs
libpam-smbpass # smb plugin 4 Nautilus
samba # smb plugin 4 Nautilus

# Util
p7zip
p7zip-full
p7zip-rar
teamviewer
vmplayer
gnome-panel
compizconfig-settings-manager
compiz-fusion-plugins-extra
#~~~ cleanup software
#pdfedit
#gimp
#avidemux
#lincoder
#gparted

# Development
#meld
#openjdk-7-jdk
#eclipse
#mercurial
#tortoisehg
#geany
#kompozer
#git

# Media
gstreamer0.10-fluendo-mp3
"""
#  proposedSoftwareText = """\
#acpicall-ion-shutdown
#"""
  tmpFile = "/tmp/.pybuntu-proposed-software"
  f = superOpenW(tmpFile)
  f.write(proposedSoftwareText)
  f.close()
  del f
  execute("nano '%s'" % tmpFile)
  software = open(tmpFile).read()
  software = getNoncommentedLines(software)
  installers = getSoftwareInstallers(software)
  execute("sudo apt-get update")
  for inst in installers:
    inst()

def patchFSProperties():
  partitions = []
  for d in os.listdir("/dev/"):
    if d.startswith("sd") and d[-1:] in [str(x) for x in xrange(0, 9)]:
      partitions.append(os.path.join("/dev", d))
  partitions.sort()
  tmpBuf = "/tmp/pybuntutmpbuf"
  prt2size = {}
  maxsize = -1
  for prt in partitions:
    execute("tune2fs -l %s > %s" % (prt, tmpBuf))
    buf = open(tmpBuf).read()
    caption = "Block count:"
    p = buf.find(caption)
    if p < 0:
      prt2size[prt] = 0
      continue
    p += len(caption)
    while p < len(buf) and buf[p] == " ": p += 1
    buf = buf[p:]
    p = buf.find("\n")
    if p < 0: p = len(buf)
    prtsize = buf[:p]
    prtsize = int(prtsize)
    prt2size[prt] = prtsize
    if maxsize < prtsize: maxsize = prtsize
  f = superOpenW(tmpBuf)
  f.write("# tune2fs patches by ubuntu:\n")
  for k, v in prt2size.items():
    if v <= 0: continue
    if v < maxsize:
      f.write("#")
    if v * 2 < maxsize:
      f.write(" ")
    f.write("sudo tune2fs -m 0 %s\n" % k)
  f.close()
  execute("nano %s" % tmpBuf)
  tune2fspatches = getNoncommentedLines(open(tmpBuf).read())
  for patch in tune2fspatches:
    execute(patch)
  ### patch fstab now
  spacechars = [" ", "\t"]
  fstabOutput = ""
  fstabfile = "/etc/fstab"
  for fstline in open(fstabfile).read().split("\n"):
    if fstline.startswith("#"):
      fstabOutput += fstline + "\n"
      continue
    tokens = []
    while len(fstline) > 0:
      p = 0
      while p < len(fstline) and fstline[p] not in spacechars: p += 1
      tokens.append(fstline[:p])
      fstline = fstline[p:]
      if len(fstline) == 0: break
      p = 0
      while p < len(fstline) and fstline[p] in spacechars: p += 1
      tokens.append(fstline[:p])
      fstline = fstline[p:]
    device = None
    if len(tokens) > 0: device = tokens[0]
    fstabOutput += "".join(tokens) + "\n"
    if len(tokens) < 7 or (device not in prt2size.keys() and not device.startswith("UUID=")) or tokens[4].find("swap") >= 0:
      continue
    if tokens[6].find("noatime,nodiratime") < 0:
      tokens[6] += ",noatime,nodiratime"
      if tokens[4].find("ext2") < 0 and tokens[4].find("ext") >= 0:
        tokens[6] += ",data=ordered,commit=30"
    #print "'%s'" % fstline[:p]
    fstabOutput += "# added by pybuntu:\n"
    fstabOutput += "#" + "".join(tokens) + "\n"
  patchedFstabfile = fstabfile + ".pybuntupatch"
  f = superOpenW(patchedFstabfile)
  f.write(fstabOutput)
  f.close()
  execute("nano %s" % patchedFstabfile)
  execute("mv %s %s" % (patchedFstabfile, fstabfile))

class GPUStateChecker:
  def __init__(self):
    self.__lastCalled = None
    self.__period = datetime.timedelta(seconds=30)
    self.__maxPeriod = datetime.timedelta(hours=3)
    self.__notPermitedDetected = False
  def __call__(self):
    if self.__lastCalled is not None and self.__lastCalled + self.__period > datetime.datetime.now():
      return
    self.__checkGPUState()
    self.__lastCalled = datetime.datetime.now()
    self.__period *= 2
    if self.__period > self.__maxPeriod:
      self.__period = self.__maxPeriod
  def __checkGPUState(self):
    if self.__notPermitedDetected:
      print "Please execute pybuntu deamon as root"
      return
    gpuStateTmpBuffer = "/tmp/.pybuntu-gpu-state"
    execute("/bin/pybuntu-ascpicall/asus1215n.sh > %s" % gpuStateTmpBuffer)
    buf = open(gpuStateTmpBuffer).read()
    if buf.find("module not loaded") >= 0:
      execute("insmod /bin/pybuntu-ascpicall/acpi_call.ko > /tmp/.pybuntu-insmod.txt 2>&1")
      if open("/tmp/.pybuntu-insmod.txt").read().find("Operation not permitted") > -1:
        self.__notPermitedDetected = True
        return
      self.__checkGPUState()
      return
    p = buf.find("appear")
    isSwitchedOn = False
    if p > -1:
      buf = buf[p:]
      isSwitchedOn = buf.find(" on") > -1
    if isSwitchedOn:
      self.__period = datetime.timedelta(seconds=5)
      execute("/bin/pybuntu-ascpicall/asus1215n.sh off")
    f = open("/tmp/.pybuntu-gpu-checker-messages.txt", "a")
    f.write(str(datetime.datetime.now()))
    f.write(" ")
    f.write(buf)
    f.close()

def startPybuntuDeamon(startinNewProcess=False):
  if startinNewProcess:
    execute("python %s start-pybuntu-deamon &" % os.path.abspath(sys.argv[0]))
    return
  initTasks = [
    PybuntuWebUI.staticStart,
  ]
  tensecondsTasks = [
    GPUStateChecker(),
  ]
  for task in initTasks:
    task()
  while True:
    time.sleep(10.0)
    for task in tensecondsTasks:
      task()

def getValueAfterMarker(text, marker, skipLeadingSpaces=True):
  p = text.find(marker)
  if p < 0: return None
  p += len(marker)
  text = text[p:]
  while skipLeadingSpaces and len(text) > 0 and text[0] in [" ", "\t", "\n"]:
    text = text[1:]
  p = text.find("\n")
  if p < 0: p = len(text)
  return text[:p]

class InfoStruct: pass

class HardwareStateInfo(InfoStruct):
  CPU_INFO_IN_FS = "/sys/devices/system/cpu"
  USB_INFO_IN_FS = "/sys/bus/usb/devices"
  BAT_INFO_IN_FS = "/proc/acpi/battery"
  class CPUInfo(InfoStruct):
    def __init__(self, name):
      self.name = name
      loc = os.path.join(HardwareStateInfo.CPU_INFO_IN_FS, name)
      self.throttling = "?" #open(os.path.join(loc, "thermal_throttle/core_throttle_count")).read()
      self.switchPsafeCmd = "cmd=switch:cpu:%s:off" % name
      self.switchPerfCmd = "cmd=switch:cpu:%s:on" % name
  class USBInfo(InfoStruct):
    def __init__(self, fsname):
      devdir = os.path.join(HardwareStateInfo.USB_INFO_IN_FS, fsname)
      self.usbFsname = fsname
      self.usbProduct = open(os.path.join(devdir, "product")).read()
      self.switchOffCmd = "cmd=switch:usb:%s:off" % fsname
      self.switchOnCmd = "cmd=switch:usb:%s:on" % fsname
  class BatteryInfo(InfoStruct):
    def __init__(self, batname):
      devdir = os.path.join(HardwareStateInfo.BAT_INFO_IN_FS, batname)
      self.battaryName = batname
      buf = open(os.path.join(devdir, "state")).read()
      self.chargeState = getValueAfterMarker(buf, "charging state:")
      self.chargeRate = getValueAfterMarker(buf, "present rate:")
      self.remainCapacity = getValueAfterMarker(buf, "remaining capacity:")
  def __init__(self):
    self.asusGpuState = "unknown"
    self.asusGpuSwitchoffCmd = "cmd=switch:ion:powersafe"
    self.asusGpuSwitchonCmd = "cmd=switch:ion:performance"
    self.cpuinfo = []
    self.usbinfo = []
    self.batinfo = []
  def fill(self):
    # asus gpu
    gpuStateTmpBuffer = "/tmp/.pybuntu-gpu-state"
    execute("/bin/pybuntu-ascpicall/asus1215n.sh > %s" % gpuStateTmpBuffer)
    buf = open(gpuStateTmpBuffer).read()
    pref = "appears to be "
    p = buf.find(pref)
    if p > -1:
      p += len(pref)
      self.asusGpuState = buf[p:]
    # cpu
    for cpuname in os.listdir(HardwareStateInfo.CPU_INFO_IN_FS):
      if not cpuname.startswith("cpu") or len(cpuname) > 4: continue
      self.cpuinfo.append(HardwareStateInfo.CPUInfo(cpuname))
    # usb
    for usbname in os.listdir(HardwareStateInfo.USB_INFO_IN_FS):
      productFile = os.path.join(HardwareStateInfo.USB_INFO_IN_FS, usbname, "product")
      if not os.path.exists(productFile): continue
      self.usbinfo.append(HardwareStateInfo.USBInfo(usbname))
    # battery
    for batname in os.listdir(HardwareStateInfo.BAT_INFO_IN_FS):
#      productFile = os.path.join(HardwareStateInfo.USB_INFO_IN_FS, batname, "state")
#      if not os.path.exists(productFile): continue
      self.batinfo.append(HardwareStateInfo.BatteryInfo(batname))

def FindAndFillTemplate(obj, type_2_template):
  tp = obj.__class__
  if tp not in type_2_template.keys():
    return False, ""
  tmpl = type_2_template[tp]
  return True, FillTemplateWithObject(tmpl, obj, type_2_template)

def FillTemplateWithObject(template, obj, type_2_template={}):
  for k, v in obj.__dict__.items():
    if isinstance(v, InfoStruct):
      manafed, text = FindAndFillTemplate(v, type_2_template)
      if manafed:
        v = text
      else:
        template = FillTemplateWithObject(templ, v)
        v = None
    if isinstance(v, list):
      l = v
      aggregated = ""
      for v in l:
        manafed, text = FindAndFillTemplate(v, type_2_template)
        if manafed:
          aggregated += " " + text
        else:
          template = FillTemplateWithObject(template, v)
      if len(aggregated) > 0:
        v = aggregated
      else:
        v = None
    if v is None: continue
    v = str(v)
    escapedName = "<%%%s%%>" % str(k)
    #print "'%s' -> '%s'" % (str(k), escapedName)
    template = template.replace(escapedName, v)
  return template

class PybuntuWebUI:
  def __staticStart(inSeparateThread=True):
    PybuntuWebUI().start(inSeparateThread)
  staticStart = staticmethod(__staticStart)
  def __staticStartSameThread():
    PybuntuWebUI.staticStart(False)
  staticStartSameThread = staticmethod(__staticStartSameThread)
  def start(self, inSeparateThread=True):
    if inSeparateThread:
      thread.start_new_thread(self.__startInternal, ())
    else:
      self.__startInternal()
  def __startInternal(self):
    try:
      server = HTTPServer(('', 1538), self.__getRequestsHandler())
      self.__printMsgToWebUITmp("Pybuntu web UI srated.")
      server.serve_forever()
    except KeyboardInterrupt:
      self.__printMsgToWebUITmp("Pybuntu web UI interrupted.")
      server.socket.close()
  def __getRequestsHandler(pybuntuWebUIInstance):
    class Handler(BaseHTTPRequestHandler):
      def do_GET(self):
        pybuntuWebUIInstance.handleHTTPRequest(self.wfile, self.path)
      def do_POST(self):
        pass
    return Handler
  def __printMsgToWebUITmp(self, message):
    f = open("/tmp/.pybuntu-web-ui", "a")
    f.write(message)
    f.close()
  ### Web functionality:
  class Request:
    def __init__(self, path):
      self.commandName = None
      self.commandArguments = None
      cmdEq = "cmd="
      p = path.find(cmdEq)
      if p > -1:
        p += len(cmdEq)
        cmdDescr = path[p:]
        p = cmdDescr.find(";")
        if p == -1: p = len(cmdDescr)
        cmdDescr = cmdDescr[:p]
        cmdDescr = cmdDescr.split(":")
        if len(cmdDescr) > 0:
          self.commandName = cmdDescr[0]
          self.commandArguments = cmdDescr[1:]
      subfolder = path.split("/")
      while len(subfolder) > 0 and len(subfolder[0]) == 0:
        subfolder = subfolder[1:]
      if len(subfolder) > 0:
        subfolder = subfolder[0]
      else:
        subfolder = "/"
      if subfolder.startswith(cmdEq): subfolder = "/"
      self.subfolder = subfolder
    def __str__(self):
      return "Cmd: '%s', (%s)" % (self.commandName, str(self.commandArguments))
  def handleHTTPRequest(self, wfile, path):
    request = PybuntuWebUI.Request(path)
    subfolder2processorMap = {
      #"/": default,
      "ttt": smarthomepageHandler,
      "sms": megafonSms,
    }
    handler = None
    if request.subfolder in subfolder2processorMap.keys():
      handler = subfolder2processorMap[request.subfolder]
    if handler is not None:
      handler(wfile, path)
      return
    hsi = HardwareStateInfo()
    hsi.fill()
    type_2_template = {
      HardwareStateInfo.CPUInfo: """\
<tr>
  <td>
    <b>CPU</b>
  </td>
  <td>
    <%name%>
  </td>
  <td>
    <%throttling%>
  </td>
  <td>
    switch: <a href="<%switchPsafeCmd%>">psafe</a> <a href="<%switchPerfCmd%>">perf</a>
  </td>
</tr>
""",
      HardwareStateInfo.USBInfo: """\
<tr>
  <td>
    <b>USB</b>
  </td>
  <td>
    <%usbFsname%>
  </td>
  <td>
    <%usbProduct%>
  </td>
  <td>
    switch: <a href="<%switchOffCmd%>">off</a> <a href="<%switchOnCmd%>">on</a>
  </td>
</tr>
""",
      HardwareStateInfo.BatteryInfo: """\
<tr>
  <td>
    <b>Battery</b>
  </td>
  <td>
    <%battaryName%>
  </td>
  <td>
    <%chargeState%> <b>||</b>
    <%chargeRate%> <b>||</b>
    <%remainCapacity%>
  </td>
  <td>
    X
  </td>
</tr>
""",
    }
    hsihtml = FillTemplateWithObject("""\
<html>
  <table border="1">
    <tr>
      <td>
        <b>Asus GPU</b>
      </td>
      <td colspan="2">
        <%asusGpuState%>
      </td>
      <td>
        switch: <a href="<%asusGpuSwitchoffCmd%>">off</a> <a href="<%asusGpuSwitchonCmd%>">on</a>
      </td>
    </tr>
    <%cpuinfo%>
    <tr>
      <td colspan="3">
        <b>[ALL CPU]</b>
      </td>
      <td>
        switch: <a href="cmd=switch:cpu:[all]:powersafe">psafe</a>
      </td>
    </tr>
    <%usbinfo%>
    <tr>
      <td colspan="3">
        <b>[ALL Storage USB]</b>
      </td>
      <td>
        switch: <a href="cmd=switch:usb:[all-storage]:off">off</a>
      </td>
    </tr>
    <%batinfo%>
  </table>
</html>
""",
      hsi, type_2_template)
    wfile.write(hsihtml)
    #wfile.write(("<html>Hello:<br>'%s'<br>'%s'<br>'%s'" + \
    #"<br><a href='cmd=qwe:1:2:3:4:567'>hello</a><br>%s</html>") % (path, str(self), str(request), hsihtml))

def smarthomepageHandler(wfile, path):
  pybuntuhome = sys.argv[0]
  pybuntuhome = os.path.split(pybuntuhome)[0]
  pybuntuhome = os.path.join(pybuntuhome, "pybuntuhome.html")
  if os.path.exists(pybuntuhome):
    wfile.write(open(pybuntuhome).read())
  else:
    wfile.write("Failed to find file: '%s'" % pybuntuhome)

def megafonSms(wfile, path):
  wfile.write("""\
<HEAD>
  <meta HTTP-EQUIV="REFRESH" content="0; url='https://sendsms.megafon.ru?addr=5155618'">
</HEAD>
""")

def onUbuntuInstalled():
  replaceVarDirectoriesWithRamfsLinks()
  insertOnUbuntuLoadedToRcLocal()
  patchFSProperties()
  proposeSoftwareInstallation()

def onUbuntuLoaded():
  replaceVarDirectoriesWithRamfsLinks(createTmpInfrastructureOnly=True)
  loadAcpicallModule()
  #switchIonGPU("off")
  startPybuntuDeamon(True)

if __name__ == "__main__":
  commandsMap = {
    "on-ubuntu-installed": onUbuntuInstalled,
    "on-ubuntu-loaded": onUbuntuLoaded,
    "start-pybuntu-deamon": startPybuntuDeamon,
    "propose-software": proposeSoftwareInstallation,
    #"test": patchFSProperties,
    "test": PybuntuWebUI.staticStartSameThread,
    }
  command = getCommand()
  if command not in commandsMap.keys():
    print "Commands:", str(commandsMap.keys())
    exit(1)
  commandExecutor = commandsMap[command]
  commandExecutor()
